

#include "board_uart.h"


/* Initialisation part. */
USART_TypeDef* COM_USART[COMn]       = {BOARD_COM1,              BOARD_COM2,              BOARD_COM3};
GPIO_TypeDef* COM_TX_PORT[COMn]      = {BOARD_COM1_TX_GPIO_PORT, BOARD_COM2_TX_GPIO_PORT, BOARD_COM3_TX_GPIO_PORT};
GPIO_TypeDef* COM_RX_PORT[COMn]      = {BOARD_COM1_RX_GPIO_PORT, BOARD_COM2_RX_GPIO_PORT, BOARD_COM3_RX_GPIO_PORT};
const uint32_t COM_USART_CLK[COMn]   = {BOARD_COM1_CLK,          BOARD_COM2_CLK,          BOARD_COM3_CLK};
const uint32_t COM_TX_PORT_CLK[COMn] = {BOARD_COM1_TX_GPIO_CLK,  BOARD_COM2_TX_GPIO_CLK,  BOARD_COM3_TX_GPIO_CLK};
const uint32_t COM_RX_PORT_CLK[COMn] = {BOARD_COM1_RX_GPIO_CLK,  BOARD_COM2_RX_GPIO_CLK,  BOARD_COM3_RX_GPIO_CLK};
const uint16_t COM_TX_PIN[COMn]      = {BOARD_COM1_TX_PIN,       BOARD_COM2_TX_PIN,       BOARD_COM3_TX_PIN};
const uint16_t COM_RX_PIN[COMn]      = {BOARD_COM1_RX_PIN,       BOARD_COM2_RX_PIN,       BOARD_COM3_RX_PIN};

/* Communication part. */
/* Common definition. */
volatile char  UART_RING_BUFFER[COMn][UART_RX_BUFFER_SIZE];
volatile char* UART_RING_BUFFER_HEAD[COMn] ={UART_RING_BUFFER[COM1],UART_RING_BUFFER[COM2],UART_RING_BUFFER[COM3]};
volatile char* UART_RING_BUFFER_TAIL[COMn] ={UART_RING_BUFFER[COM1],UART_RING_BUFFER[COM2],UART_RING_BUFFER[COM3]};
volatile int32_t UART_RING_BUFFER_RECEIVED_BYTE[COMn] = {0,0,0};

/* UART_1 RX ring buffer and so on. */
volatile char  uart_1_ring_buffer[UART1_RX_BUFFER_SIZE];
volatile char* uart_1_ring_buffer_head = uart_1_ring_buffer;
volatile char* uart_1_ring_buffer_tail = uart_1_ring_buffer;
volatile int32_t uart_1_ring_buffer_received_byte = 0;





void uart_init(void)
{
    /* UART variable structure. */
    USART_InitTypeDef uart1;
    /* Nested vector interrupt controller structure. */
    NVIC_InitTypeDef NVIC_InitStructure;

    /* Setup uart module parameters. */
    uart1.USART_BaudRate   = COM1_BAUD_RATE;
    uart1.USART_WordLength = USART_WordLength_8b;
    uart1.USART_StopBits   = USART_StopBits_1;
    uart1.USART_Parity     = USART_Parity_No;
    uart1.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    uart1.USART_Mode       = USART_Mode_Rx | USART_Mode_Tx;

    /* Initialise and enable UART module. */
    board_com_init(COM1, &uart1);

    /* Configure the NVIC Preemption Priority Bits */
    /* Enable the USART1 Interrupt */
    /* Specifies the IRQ channel to be enabled or disabled. */
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    /* Specifies the priority of specified channel. */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = USART1_PRIORITY_GROUP;
    /* Specifies the subpriority of specified channel. */
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = USART1_SUB_PRIORITY;
    /* Set state of the specified channel. */
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    /* Init NVIC. */
    NVIC_Init(&NVIC_InitStructure);

    #if 0
    /* Enable the USART2 Interrupt */
    /* Specifies the IRQ channel to be enabled or disabled. */
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    /* Specifies the priority of specified channel. */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = USART2_PRIORITY;
    /* Specifies the subpriority of specified channel. */
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = USART2_SUB_PRIORITY;
    /* Set state of the specified channel. */
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    /* Init NVIC. */
    NVIC_Init(&NVIC_InitStructure);

    /* Enable the USART3 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    /* Specifies the priority of specified channel. */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = USART3_PRIORITY;
    /* Specifies the subpriority of specified channel. */
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = USART3_SUB_PRIORITY;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    #endif

    /* Enable USARTy Receive interrupts */
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    // //USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
    /* Enable USARTy Transmit interrupts */
    // USART_ITConfig(USART1, USART_IT_TC, ENABLE);
    /* We need add some delay to wait for pin TX defined like output change state. */
    /* If we do not do that, target can lose first transmitted by our board character.*/
    // NVIC_EnableIRQ(USART1_IRQn);
    delay( 100000);
}

/**
  * @brief  Configures COM port.
  * @param  COM: Specifies the COM port to be configured.
  *   This parameter can be one of following parameters:
  *     @arg COM1
  *     @arg COM2
  *     @arg COM3
  * @param  USART_InitStruct: pointer to a USART_InitTypeDef structure that
  *   contains the configuration information for the specified USART peripheral.
  * @retval None
  */
void board_com_init(COM_TypeDef COM, USART_InitTypeDef* USART_InitStruct)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* Enable GPIO clock. */
  RCC_APB2PeriphClockCmd(COM_TX_PORT_CLK[COM] | COM_RX_PORT_CLK[COM] | RCC_APB2Periph_AFIO, ENABLE);

  /* UART module clock. */
  if (COM == COM1)
  {
    /* RCC_APB1Periph_USART21 is on RCC_APB2PeriphClockCmd. */
    RCC_APB2PeriphClockCmd(COM_USART_CLK[COM], ENABLE);
  }
  else
  {
    /* RCC_APB1Periph_USART2, RCC_APB1Periph_USART3 is on RCC_APB1PeriphClockCmd. */
    RCC_APB1PeriphClockCmd(COM_USART_CLK[COM], ENABLE);
  }

  /* Configure USART Tx as alternate function push-pull. */
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Pin   = COM_TX_PIN[COM];
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(COM_TX_PORT[COM], &GPIO_InitStructure);

  /* Configure USART Rx as input floating. */
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Pin   = COM_RX_PIN[COM];
  GPIO_Init(COM_RX_PORT[COM], &GPIO_InitStructure);

  /* USART configuration. */
  USART_Init(COM_USART[COM], USART_InitStruct);

  /* Enable USART. */
  USART_Cmd(COM_USART[COM], ENABLE);
}

/**
  * @brief  USART1  IRQ function.
  * @param  None
  * @retval None
  */
void USART1_IRQHandler(void)
{
  /* Byte was received. */
  if((USART1->SR & USART_SR_RXNE)!=0)
  {
    uint8_t ch;
    /* Read byte from UART register. */
    ch = USART1->DR;
    //UART1_rx_isr();
    UARTx_rx_isr(COM1, ch);
  }
  /* End of TX. */
  /* Bit 6 TC: Transmission complete.(RM0008) */
  if((USART1->SR & USART_SR_TC)!=0)
  {
    /* Clear TC flag*/
//    USART1->SR &= ~USART_SR_TC;
  }
  /* Bit 7 TXE: Transmit data register empty.(RM0008) */
  if((USART1->SR & USART_SR_TXE)!=0)
  {

  }
}

 /**
  * @brief  Read byte(char) from COM port.
  * @param  COM: Specifies the COM port to be configured.
  *   This parameter can be one of following parameters:
  *     @arg COM1
  *     @arg COM2
  *     @arg COM3
  * @retval Char, received byte.
  */
/* It is blocking reading. But we can make unblocking reading, checking if UART_RING_BUFFER_RECEIVED_BYTE[COMx] not ZERO. */
/* Example : USART1->DR = read_char_UART1 ();// read data from RX and send it to TX. */
char read_char_UARTx (COM_TypeDef COMx)
{
  char ch;

  /* Wait for buffer read new character. */
  while(UART_RING_BUFFER_HEAD[COMx]==UART_RING_BUFFER_TAIL[COMx]);

  /* Read character to ch. */
  ch = *UART_RING_BUFFER_TAIL[COMx];

  /* Mowe tail to next position. */
  UART_RING_BUFFER_TAIL[COMx]++;

  /* Check, if tail reached end of buffer set it to start of it. */
  if(UART_RING_BUFFER_TAIL[COMx] >=&UART_RING_BUFFER[COMx][UART_RX_BUFFER_SIZE])
  {
    UART_RING_BUFFER_TAIL[COMx] = UART_RING_BUFFER[COMx];
  }

  /* Decrease size of received bytes. */
  UART_RING_BUFFER_RECEIVED_BYTE[COMx]--;

  /* Check it for error. */
  if(UART_RING_BUFFER_RECEIVED_BYTE[COMx] <0)
  {
    UART_RING_BUFFER_RECEIVED_BYTE[COMx] = 0;
  }
  /* Return received character. */
  return(ch);
}

 /**
  * @brief  UART RX interrupt routine.
  * @param  COMx: Specifies the COM port to be configured.
  *   This parameter can be one of following parameters:
  *     @arg COM1
  *     @arg COM2
  *     @arg COM3
  * @param  ch: Received byte.
  * @retval None.
  */
void UARTx_rx_isr(COM_TypeDef COMx, uint8_t ch)
{
   /* Put character to the buffer. */
  *UART_RING_BUFFER_HEAD[COMx] = ch;
   /* Increase head pointer. */
   UART_RING_BUFFER_HEAD[COMx]++;

   /* If head pointer reach end of buffer, point it to start of buffer(ring). */
   if(UART_RING_BUFFER_HEAD[COMx] >= &UART_RING_BUFFER[COMx][UART_RX_BUFFER_SIZE])
   {
     UART_RING_BUFFER_HEAD[COMx] = UART_RING_BUFFER[COMx];
   }

   /* If head pointer reached tail pointer, we need move tail. */
   if(UART_RING_BUFFER_HEAD[COMx] == UART_RING_BUFFER_TAIL[COMx] )
   {
     UART_RING_BUFFER_TAIL[COMx]++;
     /* If tail pointer reach end of buffer, point it to start of buffer. */
     if(UART_RING_BUFFER_TAIL[COMx] >=&UART_RING_BUFFER[COMx][UART_RX_BUFFER_SIZE])
     {
       UART_RING_BUFFER_TAIL[COMx] = UART_RING_BUFFER[COMx];
     }
   }
   /* Byte receiver counter. We need to know does buffer empty or not. */
   if(UART_RING_BUFFER_RECEIVED_BYTE[COMx] < UART_RX_BUFFER_SIZE)
   {
     UART_RING_BUFFER_RECEIVED_BYTE[COMx]++;
   }
}


/**
  * @brief  Read byte from UART ring buffer.
  * @param:
  * COM_TypeDef COMx - UART port number,
  * uint8_t *ui8_ch  - pointer to character .
  * @retval:
  * int - error if timeout happend return 1 if OK return 0
  * Non blocked reading.
  */
int UARTx_Read_Byte_From_Round_Buffer(COM_TypeDef COMx, uint8_t *ui8_ch, uint16_t timeout)
{
  int result = 1 ;/* error */
  char ch;
  /* Waiting for timeout. */
  while(timeout)
  {
    /* Checking if we have at least one byte in the buffer */
    if(UART_RING_BUFFER_HEAD[COMx]==UART_RING_BUFFER_TAIL[COMx])
    {
      sys_delay(1);
      timeout--;
      /* If timeout finished set result to error. */
      if(timeout == 0)
      {
        result = 1;
      }
    }
    else
    {
      timeout = 0;
      result = 0;
    }
  }

  if(result == 0)
  {
    /* Read character to ch. */
    ch = *UART_RING_BUFFER_TAIL[COMx];

    /* Mowe tail to next position. */
    UART_RING_BUFFER_TAIL[COMx]++;

    /* Check, if tail reached end of buffer set it to start of it. */
    if(UART_RING_BUFFER_TAIL[COMx] >=&UART_RING_BUFFER[COMx][UART_RX_BUFFER_SIZE])
    {
      UART_RING_BUFFER_TAIL[COMx] = UART_RING_BUFFER[COMx];
    }

    /* Decrease size of received bytes. */
    UART_RING_BUFFER_RECEIVED_BYTE[COMx]--;

    /* Check it for error. */
    if(UART_RING_BUFFER_RECEIVED_BYTE[COMx] <0)
    {
      UART_RING_BUFFER_RECEIVED_BYTE[COMx] = 0;
    }

    /* Return received character. */
    *ui8_ch = ch;
  }
  return(result);
}


int ReceiveDataPacket(uint8_t *buffer, uint16_t length, COM_TypeDef COMx)
{
   int result = 1 ;/* error */
   uint8_t ch;
   uint16_t i = 0;
   uint16_t PacketSize  = 0;
   uint16_t Packet_CRC = 0;
   uint16_t current_CRC = 0;
   uint32_t write_cmd =0;


   result = UARTx_Read_Byte_From_Round_Buffer(COMx, &ch , 100);
   if(result == 0)
   {
      /* Looking for header string. */
      if(ch == 0x0B)
      {
          buffer[0] = ch; /* 0 th byte. */
          result = UARTx_Read_Byte_From_Round_Buffer(COMx, &ch , 100);

          if(( ch == 'W') && (result == 0))
          {
            buffer[1] = ch; /* 1 th byte. */
            result = UARTx_Read_Byte_From_Round_Buffer(COMx, &ch , 100);
            if((ch == 'R') && (result == 0))
            {
              buffer[2] = ch; /* 2 th byte. */
              result = UARTx_Read_Byte_From_Round_Buffer(COMx, &ch , 100);

              if((ch == 'T') && (result == 0))
              {
                buffer[3] = ch; /* 3 th byte. */
                result = UARTx_Read_Byte_From_Round_Buffer(COMx, &ch , 100);

                buffer[4] = ch; /* LSB of size of packet. */
                result = UARTx_Read_Byte_From_Round_Buffer(COMx, &ch , 100);
                buffer[5] = ch; /* MSB of size of packet. */

                /* Reading size of packet. */
                PacketSize = buffer[4] + buffer[5]*0xFF;

                /* Reading all data from data packet. */
                i=0;
                while(i < PacketSize)
                {
                  result = UARTx_Read_Byte_From_Round_Buffer(COMx, &ch , 100);
                  if( (i+6) < length)
                  {
                    buffer[i+6] = ch;
                    i++;
                  }
                  else
                  {
                    result =1; /* error */
                  }
                }
                current_CRC =  CRC16_alg( &buffer[6], PacketSize-2);//header size = 4 , plus two bytes of PacketSize, so, start address of data block is &&buffer[6]
                Packet_CRC = buffer[PacketSize + 6 - 1]* 0x100;
                Packet_CRC = Packet_CRC + buffer[PacketSize + 6 -2];
                /* If CRC is correct lets set PID coefficients to PID structure. */
                if(Packet_CRC == current_CRC)
                {
                    write_cmd = buffer[9];
                    write_cmd = (write_cmd <<8) + buffer[8];
                    write_cmd = (write_cmd <<8) + buffer[7];
                    write_cmd = (write_cmd <<8) + buffer[6];
                    /*TODO: Here I will use index. */
                    i=10;

                    /* Pitch */
                    PID[Pitch].p_gain     = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Pitch].p_dyn_gain = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Pitch].i_gain     = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Pitch].i_dyn_gain = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Pitch].d_gain     = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Pitch].d_dyn_gain = buffer[i] + buffer[i+1] * 0x100; /* 20,21 */
                    i=i+2;

                    /* Roll */
                    PID[Roll].p_gain     = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Roll].p_dyn_gain = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Roll].i_gain     = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Roll].i_dyn_gain = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Roll].d_gain     = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Roll].d_dyn_gain = buffer[i] + buffer[i+1] * 0x100; /* 32,33 */
                    i=i+2;

                    /* Yaw */
                    PID[Yaw].p_gain     = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Yaw].p_dyn_gain = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Yaw].i_gain     = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Yaw].i_dyn_gain = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Yaw].d_gain     = buffer[i] + buffer[i+1] * 0x100;
                    i=i+2;
                    PID[Yaw].d_dyn_gain = buffer[i] + buffer[i+1] * 0x100; /* 44,45 */
                    /* 46 and 47 is for CRC and I do not use them. */

                    /*
                    * TODO: Here we should decide what to do with write cmd.
                    * We can write PIDs to RAM or to flash too.
                    */


                 }
               }/*T*/
            }/*R*/
          }/*W*/
      }/* if(ch == 0x0B) */
   }/* if result */

   return(result);
}


#if 0

        buffer[0] = ch;
        while(i < length )
        {
          result = UARTx_Read_Byte_From_Round_Buffer(COMx, &ch , 100);
          if(result == 0)
          {
            buffer[i+1] = ch;
            i++;
              if(i == 23)
              {
                i=24;
              }
          }
          else
          {
            i = length;/* return from while. */
          }
        }


#endif






/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
int fputc(int ch, FILE *f)
{
  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(COM_USART[TERMINAL_OUTPUT], USART_FLAG_TC) == RESET)
  {}
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART */
  USART_SendData(COM_USART[TERMINAL_OUTPUT], (uint8_t) ch);
 // /* Loop until the end of transmission */
 // while (USART_GetFlagStatus(COM_USART[TERMINAL_OUTPUT], USART_FLAG_TC) == RESET)
 // {}
  return ch;
}

/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
uint8_t board_fputc(uint8_t ch)
{
  /*
   * First of all we will watit for and of transmission and ready UART
   * to avoid disapearing of the first symbol.
   */
  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(COM_USART[TERMINAL_OUTPUT], USART_FLAG_TC) == RESET)
  {}
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART */
  USART_SendData(COM_USART[TERMINAL_OUTPUT], ch);
  return ch;
}





/* TBR */
char read_char_UART1 (void)
{
  char ch;
  /* Wait for buffer read new character. */
  while(uart_1_ring_buffer_head==uart_1_ring_buffer_tail);
  /* Read character to ch. */
  ch = *uart_1_ring_buffer_tail;
  /* Mowe tail to next position. */
  uart_1_ring_buffer_tail++;
  /* Check, if tail reached end of buffer set it to start of it. */
  if(uart_1_ring_buffer_tail >=&uart_1_ring_buffer[UART1_RX_BUFFER_SIZE])
  {
    uart_1_ring_buffer_tail = uart_1_ring_buffer;
  }
  /* Decrease size of received bytes. */
  uart_1_ring_buffer_received_byte--;
  /* Check it for error. */
  if(uart_1_ring_buffer_received_byte <0)
  {
    uart_1_ring_buffer_received_byte = 0;
  }
  /* Return received character. */
  return(ch);
}

/* TBR */
void UART1_rx_isr(void)
{
   uint8_t ch;

   /* UART1 receiver */
   ch = USART1->DR;

   /* Put character to the buffer. */
  *uart_1_ring_buffer_head = ch;
   uart_1_ring_buffer_head++;

   /* If head reached end of buffer, set it to start of buffer. */
   if(uart_1_ring_buffer_head >= &uart_1_ring_buffer[UART1_RX_BUFFER_SIZE])
   {
     uart_1_ring_buffer_head = uart_1_ring_buffer;
   }

   /* If head reached tail, we need move tail. */
   if(uart_1_ring_buffer_head == uart_1_ring_buffer_tail )
   {
     uart_1_ring_buffer_tail++;
     /* If tail reached end of buffer,set it to start of buffer. */
     if(uart_1_ring_buffer_tail >=&uart_1_ring_buffer[UART1_RX_BUFFER_SIZE])
     {
       uart_1_ring_buffer_tail = uart_1_ring_buffer;
     }
   }

   if(uart_1_ring_buffer_received_byte < UART1_RX_BUFFER_SIZE)
   {
     uart_1_ring_buffer_received_byte++;
   }

}




